package vfs.webservice.impl;

import vfs.service.impl.VFSNodeServiceImpl;
import vfs.service.VFSNodeService;
import java.sql.Connection;
import vfs.obj.entity.VFSUser;
import javax.ws.rs.QueryParam;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import java.util.HashMap;
import java.util.Map;
import vfs.filter.VFSFilter.VFSFilterOperator;
import vfs.filter.impl.VFSFilterImpl;
import vfs.filter.VFSFilter;
import vfs.webservice.VFSNodeWebService;
import vfs.obj.entity.VFSNodeType;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.simple.JSONValue;
import vfs.obj.entity.VFSNode;
import vfs.except.VFSCreationException;
import vfs.except.VFSModificationException;
import vfs.persist.util.VFSPersistUtil;
import vfs.service.VFSUserService;
import vfs.service.impl.VFSUserServiceImpl;


/**
 *
 * @author Matthew Eavenson <durandal@uga.edu>
 * 
 */
@Path("/node")
public class VFSNodeWebServiceImpl implements VFSNodeWebService{
    
    @GET @Path("/info")
    @Produces("application/json")
    @Override
    public String info( @QueryParam("uid")  String uid, 
                        @QueryParam("dir")  Long workingDir, 
                        @QueryParam("path") String pathStr ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        Map<String,Object> response = new HashMap<String,Object>();
        
        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode wDir = getNode(nService, workingDir);
            if(wDir != null){
                VFSNode node = nService.getNode(wDir, pathStr);
                if(node != null){
                    Map<String,Object> info = getNodeInfo(node, nService, true);
                    String nodePath = nService.getPath(node);
                    info.put("path", nodePath);
                    response.put("result", info);
                }else{
                    response.put("error", "No such file or directory");
                }
            }else response.put("error", "No such file or directory");
        }

        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/create")
    @Produces("application/json")
    @Override
    public String create( @QueryParam("uid")      String uid, 
                          @QueryParam("dir")      Long workingDir, 
                          @QueryParam("name")     String name, 
                          @QueryParam("access")   String access, 
                          @QueryParam("loc")      String location, 
                          @QueryParam("type")     Long type ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        Map<String,Object> response = new HashMap<String,Object>();

        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode wDir = getNode(nService, workingDir);
            if(wDir != null){
                VFSNodeType nodeType = nService.getType(wDir);
                try{
                    VFSNode node = nService.create(wDir, name, access, location, nodeType);
                    response.put("result", getNodeInfo(node, nService, true));
                }catch(VFSCreationException ex){
                    response.put("error", ex.getMessage());
                }
            }else response.put("error", "No such file or directory");
        }

        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/remove")
    @Produces("application/json")
    @Override
    public String remove( @QueryParam("uid")     String uid, 
                          @QueryParam("node")    Long nodeId, 
                          @QueryParam("path")    String pathStr,
                          @QueryParam("recurse") Boolean recursive ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        Map<String,String> response = new HashMap<String,String>();
        
        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode node = getNode(nService, nodeId);
            try{
                nService.remove(node, pathStr, recursive != null? recursive : false);
                response.put("result", "Remove successful");
            }catch(VFSModificationException ex){
                response.put("error", ex.getMessage());
            }
        }
        
        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/list")
    @Produces("application/json")
    @Override
    public String list( @QueryParam("uid")     String uid, 
                        @QueryParam("node")    Long nodeId, 
                        @QueryParam("path")    String pathStr, 
                        @QueryParam("verbose") Boolean verbose ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        
        Map<String,Object> response = new HashMap<String,Object>();
        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode node = getNode(nService, nodeId);
            if(node != null){
                List<Map<String,Object>> nodeList = new ArrayList<Map<String,Object>>();
                for(Iterator<VFSNode> children = nService.list(node, pathStr); children.hasNext();){
                    VFSNode child = children.next();
                    nodeList.add(getNodeInfo(child, nService, verbose));
                }
                response.put("result", nodeList);
            }else response.put("error", "No such file or directory");
        }

        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/rename")
    @Produces("application/json")
    @Override
    public String rename( @QueryParam("uid")  String uid, 
                          @QueryParam("node") Long nodeId, 
                          @QueryParam("name") String name ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        Map<String,String> response = new HashMap<String,String>();
       
        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode node = getNode(nService, nodeId);
            try{
                nService.rename(node, name);
                response.put("result", "Rename successful");
            }catch(VFSModificationException ex){
                response.put("error", ex.getMessage());
            }
        }
        
        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/moveByPath")
    @Produces("application/json")
    @Override
    public String move( @QueryParam("uid")  String uid, 
                        @QueryParam("dir")  Long nodeId, 
                        @QueryParam("path") String srcPathStr, 
                        @QueryParam("dest") String destPathStr ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);        
        Map<String,String> response = new HashMap<String,String>();

        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode node = getNode(nService, nodeId);
            try{
                nService.move(node, srcPathStr, destPathStr);
                response.put("result", "Move successful");
            }catch(VFSModificationException ex){
                response.put("error", ex.getMessage());
            }
        }
        
        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    @GET @Path("/moveById")
    @Produces("application/json")
    @Override
    public String move( @QueryParam("uid")  String uid, 
                        @QueryParam("node") Long nodeId, 
                        @QueryParam("dest") Long destId ){
        
        Connection conn = VFSPersistUtil.connect();
        VFSUserService uService = new VFSUserServiceImpl(conn);
        VFSUser user = uService.getUser(uid);
        Map<String,String> response = new HashMap<String,String>();
        
        if(user == null){
            response.put("error", "Invalid user id");
        }else{
            VFSNodeService nService = new VFSNodeServiceImpl(conn, user);
            VFSNode node = getNode(nService, nodeId);
            VFSNode dest = getNode(nService, destId);
            try{
                nService.move(node, dest);
                response.put("result", "Move successful");
            }catch(VFSModificationException ex){
                response.put("error", ex.getMessage());
            }
        }
        
        close(conn);
        return JSONValue.toJSONString(response);
    }
    
    private VFSNode getNode(VFSNodeService service, Long nodeId){
        VFSFilter filter = new VFSFilterImpl();
        filter.addConstraint("id", nodeId+"", VFSFilterOperator.EQ);
        Iterator<VFSNode> nodes = service.getNodes(filter);
        if(nodes.hasNext()){
            return nodes.next();
        }
        return null;
    }
    
    private Map<String,Object> getNodeInfo(VFSNode node, VFSNodeService service, Boolean verbose){
        Map<String,Object> info = new HashMap<String,Object>();
        boolean children = service.hasChildren(node);
        info.put("id", node.getId());
        info.put("name", node.getName());
        info.put("hasChildren", children);
        if(verbose != null && verbose){
            VFSNodeType type = service.getType(node);
            if(type != null){
                info.put("typeId", type.getId());
                info.put("typeName", type.getName());
            }
            info.put("createdOn", node.getCreationDate().toString());
            info.put("modifiedOn", node.getModifiedDate().toString());
            info.put("access", node.getPublicAccess().toString());
        }
        return info;
    }
    
    private void close(Connection conn){
        try{ conn.close();
        }catch(Exception ex){ ex.printStackTrace(); }
    }
    
}
